package com.eic.framework.core.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.eic.framework.core.util.CreateAndUpdateMetaUtils;
import com.ruoyi.common.core.redis.RedisCache;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 此处重载的方法，启用缓存
 */
public class ServiceCacheImpl<M extends BaseMapper<T>, T> extends ServicePlusImpl<M,T>{
    @Autowired
    protected RedisCache redisCache;

    @Override
    @Transactional
    public boolean updateById(T entity) {
        boolean ret=super.updateById(entity);
        String id=null;
        try{
            id= CreateAndUpdateMetaUtils.getMeta(getEntityClass()).getPrimaryField().get(entity).toString();
        }catch (Exception e){
            throw new RuntimeException("获取主键ID失败");
        }
        //只删除
        redisCache.delCacheMapValue(getCacheName(),id);
        return ret;
    }

    @Override
    public T getById(Serializable id) {
        if(id==null || StrUtil.isBlank(id.toString())){
            return null;
        }
        T t=redisCache.getCacheMapValue(getCacheName(),id.toString());
        if(t==null && !redisCache.existsCacheMap(getCacheName(),id.toString())){
            t=super.getById(id);
            //保存空值
            redisCache.setCacheMapValue(getCacheName(),id.toString(),t);
        }
        return t;
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> idList) {
        idList=idList.stream().distinct().collect(Collectors.toList());
        //首先从缓存中查询，并选择没有查询结果的ID
        List<T> cacheList=redisCache.<T>getMultiCacheMapValue(getCacheName(),idList.stream().map(id->id.toString()).collect(Collectors.toList()));
        Set cacheIds=new HashSet();
        for(T t:cacheList){
            if(t!=null){
                try{
                    cacheIds.add(CreateAndUpdateMetaUtils.getMeta(getEntityClass()).getPrimaryField().get(t));
                }catch (Exception e){
                    throw new RuntimeException("获取主键ID失败");
                }
            }
        }
        Set noCacheIds=new HashSet();
        idList.forEach( id ->{
            if(!cacheIds.contains(id)){
                noCacheIds.add(id);
            }
        });
        //缓存中没有结果，先判断缓存中是否存在，再查数据库
        Iterator itr=noCacheIds.iterator();
        int checked=0;
        int notExists=0;
        while(itr.hasNext()){
            checked++;
            if(!redisCache.existsCacheMap(getCacheName(),itr.next().toString())){
                notExists++;
                //缓存中不存在较多，直接查数据库
                if(checked>=4 && ((float)notExists)/checked>0.5){
                    break;
                }
            }else{
                itr.remove();
            }
        }
        //查数据库
        List<T> dbList= null;
        if(noCacheIds.size()>0){
            dbList=super.listByIds(noCacheIds);
            //缓存数据
            dbList.forEach(o -> {
                try{
                    Object id=CreateAndUpdateMetaUtils.getMeta(getEntityClass()).getPrimaryField().get(o);
                    redisCache.setCacheMapValue(getCacheName(),id.toString(),o);
                    noCacheIds.remove(id);
                }catch (Exception e){
                    throw new RuntimeException("获取主键ID失败");
                }
            });
            //缓存无查询结果ID
            noCacheIds.forEach(id ->{
                redisCache.setCacheMapValue(getCacheName(),id.toString(),null);
            });
        }else{
            dbList=new ArrayList<>();
        }
        for(T t:cacheList){
            if(t!=null){
                dbList.add(t);
            }
        }
        return dbList;
    }

    @Override
    public boolean removeById(Serializable id) {
        boolean ret = super.removeById(id);
        //可以不删除，不需要启用事务
        redisCache.delCacheMapValue(getCacheName(),id.toString());
        return ret;
    }

    @Override
    @Transactional
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        boolean ret = super.removeByIds(idList);
        //可以不删除，不需要启用事务
        redisCache.delCacheMapValue(getCacheName(),idList.stream().map(id->id.toString()).collect(Collectors.toList()).toArray(new String[0]));
        return ret;
    }

    private String cacheName;
    protected void delCache(Serializable id){
        redisCache.delCacheMapValue(getCacheName(),id.toString());
    }
    protected String getCacheName(){
        if(cacheName==null){
            cacheName=AopUtils.getTargetClass(this).getName();
        }
        return cacheName;
    }
}
